﻿using System;
using System.Collections.Generic;

using mvcForum.Core;
using mvcForum.Core.Interfaces.Services;
using mvcForum.Core.Specifications;
using mvcForum.Core.Interfaces.Data;

namespace mvcForum.Web.Services {

	public class ForumAccessService : IForumAccessService {
		private readonly IRepository<ForumAccess> accessRepo;
		private readonly IRepository<Group> groupRepo;
		private readonly IGroupService groupService;

		public ForumAccessService(IRepository<ForumAccess> accessRepo, IRepository<Group> groupRepo, IGroupService groupService) {
			this.accessRepo = accessRepo;
			this.groupService = groupService;
			this.groupRepo = groupRepo;
		}

		public AccessFlag GetAccessFlag(Core.Forum forum, ForumUser user) {
			if (forum == null) {
				throw new ArgumentNullException("forum");
			}

			// Default access is: None!
			AccessFlag output = AccessFlag.None;

			// Any authenticated user?
			if (user != null) {
				// Let's get the list of groups this user belongs to.
				IEnumerable<Group> groups = this.groupService.GetGroups(user);
				foreach (Group group in groups) {
					// Get the ForumAccess for the given groups!
					ForumAccess forumAccess = this.accessRepo.ReadOne(new ForumAccessSpecifications.SpecificForumAndGroup(forum, group));
					// Any access flag for this group/forum combination?
					if (forumAccess != null) {
						// Let's OR them to get the correct access for the user!
						output = output | forumAccess.AccessMask.AccessFlag;
					}
				}
			}
			else {
				// Anonymous user!
				// Get the guest group and return the accessflag (if any!)
				Group group = this.groupRepo.ReadOne(new GroupSpecifications.SpecificName("Guest"));
				// Get the ForumAccess of the forum/group combination.
				ForumAccess access = this.GetForumAccess(forum, group);
				// Did we get one?
				if (access != null) {
					// Let's return the access flag then.
					output = access.AccessMask.AccessFlag;
				}
			}

			return output;
		}

		public Boolean HasAccess(Forum forum, ForumUser user, AccessFlag flag) {
			return (this.GetAccessFlag(forum, user) & flag) == flag;
		}

		public ForumAccess GetForumAccess(Forum forum, Group group) {
			// Return the ForumAccess for the given group and forum.
			return this.accessRepo.ReadOne(new ForumAccessSpecifications.SpecificForumAndGroup(forum, group));
		}
	}
}